home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
076-100
/
077
/
language.doc
/
optype.ref
< prev
next >
Wrap
Text File
|
1995-03-13
|
9KB
|
297 lines
XV. Operator Types
The basic syntax of operator types was given previously. They will be
discussed here by means of an example, the construction of a complex
type based on integers. First, we give an include file which would be
referenced by programs wanting to use the complex number package:
type Complex_t = ("_cmplx", struct {int c_real, c_imag},
OPADD | OPSUB | OPMUL | OPDIV | OPNEG |
OPABS | OPCPR | OPPUT | OPGET);
Complex_t I = (0, 1);
This declares operator type 'Complex_t' which can be used with the
binary '+', '-', '*' and '/' operators, with the unary '-', and '|'
operators, which can be compared, and which can be read/written. The
type is implemented as a structure containing two integers, and the
routines the compiler will call will all start with "_cmplx". Also
declared is a complex constant, 'I', whose value is given using a
structure constant based on the base type of Complex_t. Using these
declarations, we could write the following code fragment:
proc main()void:
Complex_t a, b, c;
a := Complex_t(0, 0);
b := I;
write("Enter c: ");
readln(c);
if c = Complex_t(0, 0) then
c := a * I;
b := b - (a / b);
elif c < Complex_t(0, 0) then
c := -c;
fi;
writeln("New a, b, c are: ", a, b, c);
corp;
The various 'OPxxx' names used in the above include file are bitwise
'or'ed together to produce a 16 bit value giving the operations allowed.
Definitions of these bits can be found in file "opdef.g", as follows:
OPADD - the binary '+' operator
OPSUB - the binary '-' operator
OPMUL - the binary '*' operator
OPDIV - the binary '/' operator
OPMOD - the binary '%' operator
OPNEG - the unary '-' operator
OPABS - the unary '|' operator
OPIOR - the binary '|' operator
OPAND - the binary '&' operator
OPXOR - the binary '><' operator
OPSHL - the binary '<<' operator
OPSHR - the binary '>>' operator
OPNOT - the unary '~' operator
OPCPR - the binary comparison operators
OPPUT - text output using 'write' and 'writeln'
OPGET - text input using 'read' and 'readln'
The operators all have their normal precedence. The various operators
take arguments of the operator type and return a result of that type.
Exceptions to this are the shift operators, whose right operand must
be a numeric value, and the comparison operator, which yields a boolean
result. It is suggested that any uses of operator types maintain some
semblance of relation to the operators' normal meanings.
Only a skeleton of the definition file for the above complex type will
be shown. The important things are the calling sequences used.
#util.g
type Complex_t = struct {int c_real, c_imag};
uint STACK_SIZE = 10;
[10] Complex_t Stack;
uint StackPointer;
/* the psh and pop routines must be provided with ALL operator type
implementations, regardless of what else is provided */
/* _cmplxpsh - called to push a value onto our stack */
proc _cmplxpsh(*Complex_t x)void:
if StackPointer = STACK_SIZE then
writeln();
writeln("*** Complex_t stack overflow - aborting. ***");
exit(1);
fi;
Stack[StackPointer] := x*;
StackPointer := StackPointer + 1;
corp;
/* _cmplxpop - pop a value from our stack. */
proc _cmplxpop(*Complex_t x)void:
StackPointer := StackPointer - 1;
x* := Stack[StackPointer];
corp;
/* _cmplxadd - add the two values on top of the stack. */
proc _cmplxadd()void:
StackPointer := StackPointer - 1;
Stack[StackPointer - 1].c_real :=
Stack[StackPointer - 1].c_real + Stack[StackPointer].c_real;
Stack[StackPointer - 1].c_imag :=
Stack[StackPointer - 1].c_imag + Stack[StackPointer].c_imag;
corp;
/* similar for _cmplxsub, _cmplxmul, _cmplxdiv */
/* _cmplxneg - negate the top of stack value */
proc _cmplxneg()void:
Stack[StackPointer - 1].c_real :=
- Stack[StackPointer - 1].c_real;
Stack[StackPointer - 1].c_imag :=
- Stack[StackPointer - 1].c_imag;
corp;
/* similar for _cmplxabs (if you want to define an absolute value
operator that returns a complex result - if you want a routine
that returns the integral norm, then you must pick a name for
it, implement it here, and include a declaration for it in the
include file) */
/* _cmplxcpr - the comparison routine - return -1, +1 or 0 */
proc _cmplxcpr()short:
int leftSquared, rightSquared;
StackPointer := StackPointer - 1;
rightSquared := Stack[StackPointer].c_real *
Stack[StackPointer].c_real +
Stack[StackPointer].c_imag *
Stack[StackPointer].c_imag;
StackPointer := StackPointer - 1;
leftSquared := Stack[StackPointer].c_real *
Stack[StackPointer].c_real +
Stack[StackPointer].c_imag *
Stack[StackPointer].c_imag;
if leftSquared < rightSquared then
make(-1, short) /* force the result type of the if */
elif leftSquared > rightSquared then
+1
else
0
fi
corp;
/* doing read/write on operator types requires careful interaction
with the innards of Draco's run-time system. The special channel
expression '*' means "this is a call to read/write from within
a call to read/write - use the channel that is already set up".
In this situation, the read/write constructs DO NOT return a
boolean success/fail value, and an internal routine must be
called to make the check. The special routines that can be called
are as follows:
_channelPutChar(char ch)void -
write the character on the current output text channel
_channelGetChar()char -
get the next character from the current input text channel
_channelUnGetChar(char ch) -
stuff the character back into the current input text channel.
Only ONE character may be put back this way.
_channelError(ushort errorCode)void -
assert an error with the given code (from util.g) on the
current input text channel.
_channelHadError()bool -
return 'true' if the current input text channel has had an
error during the current top-level read/readln operation.
_channelSkip()void -
skip past whitespace (blanks and tabs) in the current input
text channel.
_readln()void -
swallow the remainder of the current input line and move on
to the next input line.
_writeln()void -
terminate the current output line and move on to the next
*/
/* _cmplxput - write a complex number out on the current channel */
proc _cmplxput()void:
StackPointer := StackPointer - 1;
write(*; '(', Stack[StackPointer].c_real, ", ",
Stack[StackPointer].c_imag, ')');
/* we could have also used _channelPutChar to output the single
characters - this would have been more efficient */
corp;
/* _cmplxget - read a complex number in from the current channel */
proc _cmplxget(*Complex_t x)void:
extern
_channelSkip()void,
_channelGetChar()char,
_channelHadError()bool,
_channelUnGetChar(char ch)void,
_channelError(ushort errorCode)void;
char ch;
_channelSkip();
ch := _channelGetChar();
if ch = '(' then
read(*; x*.c_real);
if not _channelHadError() then
_channelSkip();
ch := _channelGetChar();
if ch = ',' then
read(*; x*.c_imag);
if not _channelHadError() then
_channelSkip();
ch := _channelGetChar();
if ch ~= ')' then
_channelUnGetChar(ch);
_channelError(CH_BADCHAR);
fi;
fi;
else
_channelUnGetChar(ch);
_channelError(CH_BADCHAR);
fi;
fi;
else
_channelUnGetChar(ch);
_channelError(CH_BADCHAR);
fi;
corp;
To solidify all of this somewhat, if we have the following fragment:
*********
Operator types being untested on the Amiga version of the compiler, I'll
leave this an 8080 example for now.
*********
proc nonrec test()void:
Complex_t c1, c2;
if read(c1) then
if c1 < c2 then
writeln(c1 + c2);
fi;
else
c1 := - c2;
fi;
corp;
It would turn into something like the following (8080 version):
test proc
; a bunch of extern's that I'll omit
c1 ds 4
c2 ds 4
code
lxi h,c1
push h
call _setstdin
call _cmplxget
call _unchannel
ana a
jnz L2
lxi h,c1
call _cmplxpsh
lxi h,c2
call _cmplxpsh
call _cmplxcpr
ana a
jp L1
lxi h,c1
push h
call _cmplxpsh
lxi h,c2
push h
call _cmplxpsh
call _cmplxadd
call _setstdout
call _cmplxput
call _writeln
call _unchannel
L1 jmp L3
L2 lxi h,c1
push h
lxi h,c2
push h
call _cmplxpsh
call _cmplxneg
call _cmplxpop
L3 ret
corp